package com.clp.protocol.iec104.client.master_state;

import com.clp.protocol.iec104.apdu.Apdu;
import com.clp.protocol.iec104.client.Master;
import com.clp.protocol.iec104.connect.state.StateFul;

import java.util.LinkedList;
import java.util.List;

/**
 * 主站状态管理：提供主站状态信息的查询、指定状态的获取
 */
public class MasterStateManager implements MasterStateInfo, StateFul {
    private final Master master;
    private final LinkedList<MasterState> masterStates = new LinkedList<>();

    public MasterStateManager(Master master) {
        this.master = master;

        addState(new T0T1T2T3MasterState(this, master.t0Seconds(), master.t1Seconds(), master.t2Seconds(), master.t3Seconds()));
        addState(new DtMasterState(this, 3));
        addState(new RecvInitEndMasterState(this));
        addState(new TotalCall100MasterState(this, master.totalCall100PeriodSeconds()));
        addState(new TotalCall101MasterState(this, master.totalCall101PeriodSeconds()));
        addState(new TcMasterState(this));
        addState(new TaMasterState(this));
    }

    /**
     * 添加主站状态
     * @param masterState
     */
    private void addState(MasterState masterState) {
        masterStates.addLast(masterState);
    }

    @SuppressWarnings("unchecked")
    public <T extends MasterState> T getState(Class<T> stateClass) {
        for (MasterState state : masterStates) {
            if (state.getClass() == stateClass) {
                return ((T) state);
            }
        }
        throw new RuntimeException("找不到对应的状态类：" + stateClass.getName());
    }

    public Master getMaster() {
        return master;
    }

    @Override
    public void reset() {
        masterStates.forEach(MasterState::reset);
    }

    @Override
    public Apdu updateBySending(Apdu apdu) {
        for (int i = masterStates.size() - 1; i >= 0 ; i--) {
            apdu = masterStates.get(i).updateBySending(apdu);
        }
        return apdu;
    }

    @Override
    public Apdu updateByRecving(Apdu apdu) {
        for (MasterState state : masterStates) {
            apdu = state.updateByRecving(apdu);
        }
        return apdu;
    }

    @Override
    public void startMonitorTask() {
        masterStates.forEach(MasterState::startMonitorTask);
    }

    @Override
    public void tryStopMonitorTask() {
        masterStates.forEach(MasterState::tryStopMonitorTask);
    }

    @Override
    public boolean isStartedDt() {
        return getState(DtMasterState.class).isStartedDt();
    }

    @Override
    public boolean isRecvedInitEnd() {
        return getState(RecvInitEndMasterState.class).isRecvedInitEnd();
    }

    @Override
    public boolean isTestingFr() {
        return getState(T0T1T2T3MasterState.class).isTestingFr();
    }

    @Override
    public boolean isDoingTotalCall100() {
        return getState(TotalCall100MasterState.class).isDoingTotalCall100();
    }

    @Override
    public boolean isDoingTotalCall101() {
        return getState(TotalCall101MasterState.class).isDoingTotalCall101();
    }

    @Override
    public List<Integer> listAllDoingTcAddrs() {
        return getState(TcMasterState.class).listAllDoingTcAddrs();
    }

    @Override
    public List<TcMasterState.PtState> listAllDoingTcPtStates() {
        return getState(TcMasterState.class).listAllDoingTcPtStates();
    }

    @Override
    public boolean isDoingOnePointTcSelect(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingOnePointTcSelect(infoObjAddr);
    }

    @Override
    public boolean isDoingTwoPointTcSelect(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingTwoPointTcSelect(infoObjAddr);
    }

    @Override
    public boolean isDoingOnePointTcExecute(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingOnePointTcExecute(infoObjAddr);
    }

    @Override
    public boolean isDoingTwoPointTcExecute(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingTwoPointTcExecute(infoObjAddr);
    }

    @Override
    public List<TaMasterState.PtState> listAllDoingTaPtStates() {
        return getState(TaMasterState.class).listAllDoingTaPtStates();
    }

    @Override
    public boolean isDoingTaSelectNormalized(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectNormalized(infoObjAddr);
    }

    @Override
    public boolean isDoingTaSelectScaled(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectScaled(infoObjAddr);
    }

    @Override
    public boolean isDoingTaSelectFloat(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectFloat(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteNormalized(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteNormalized(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteScaled(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteScaled(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteFloat(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteFloat(infoObjAddr);
    }
}
